package com.my.aslife.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.my.aslife.mapper.DemandMapper;
import com.my.aslife.mapper.TaskMapper;
import com.my.aslife.module.common.Constant;
import com.my.aslife.module.common.DemandStatus;
import com.my.aslife.module.common.RedisConstant;
import com.my.aslife.module.common.ResponseResult;
import com.my.aslife.module.entity.Demand;
import com.my.aslife.module.entity.Task;
import com.my.aslife.module.entity.UserDetail;
import com.my.aslife.service.DemandService;
import com.my.aslife.service.IUserService;
import com.my.aslife.service.TaskService;
import com.my.aslife.service.UserDetailService;
import com.my.aslife.utils.CheckSensitiveUtil;
import com.my.aslife.utils.SerializeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author mayuan
 * @description TODO
 */
@Service
@Slf4j
@Transactional
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private DemandMapper demandMapper;

    @Autowired
    @Lazy
    private DemandService demandService;

    @Autowired
    private UserDetailService userDetailService;

    @Autowired
    @Lazy
    private IUserService userService;

    /**
     *  定时任务 每 10s 开始扫描一次
     */
    @Scheduled(cron = "*/10 * * * * ?")
    public void executeTask() {
        String key = RedisConstant.TASK;
        Long listSize = stringRedisTemplate.opsForList().size(RedisConstant.TASK);
        if (listSize != null) {
            for (int i = 0; i < listSize; i++) {
                String taskString = stringRedisTemplate.opsForList().rightPop(key);
                try {
                    Task task = SerializeUtil.objectMapperToObject(taskString, Task.class);
                    log.debug("开始执行任务：{}", task.getTaskId());
                    // 自动检查敏感词
                    Map<String, Integer> sensitiveMap = CheckSensitiveUtil.matchWords(task.getText());
                    // 允许发布
                    if (sensitiveMap.size() == 0) {
                        log.info("允许发布");
                        demandMapper.checkDemandContext(DemandStatus.PUBLISHED.getType(),
                                Constant.HANDLER_ID, task.getTaskId(), null);

                        taskMapper.updateTask(DemandStatus.PUBLISHED.getType(), task.getTaskId());
                    } else {
                        // 有敏感词，发布失败
                        StringBuilder ans = new StringBuilder();
                        StringBuilder tmp = new StringBuilder();
                        ans.append("敏感词：");
                        for (String sensitive : sensitiveMap.keySet()) {
                            tmp.append(sensitive).append(",");
                            ans.append(sensitive).append(",");
                        }
                        log.info("敏感词：{}", ans);

                        // 记录用户违规数据
                        // taskID 查询需求任务
                        ResponseResult<Demand> responseResult = demandService.queryDemandByDemandKey(task.getTaskId());
                        Demand demand = responseResult.getData();
                        ResponseResult<UserDetail> userDetailResponseResult = userDetailService.queryUserDetailInfoByUID(Long.valueOf(demand.getUid()));
                        UserDetail userDetailData = userDetailResponseResult.getData();

                        // 设置违规用户状态
                        userService.setUserIllegalStatus(Long.valueOf(demand.getUid()));

                        if (userDetailData == null) {
                            UserDetail userDetail = new UserDetail();
                            userDetail.setUid(demand.getUid());
                            userDetail.setIllegalTimes(1);
                            userDetail.setScore(-10);
                            userDetail.setIllegalContent(tmp.toString());
                            userDetailService.save(userDetail);
                        } else {
                            userDetailData.setScore(userDetailData.getScore() - 10);
                            userDetailData.setIllegalTimes(userDetailData.getIllegalTimes() + 1);
                            userDetailData.setIllegalContent(userDetailData.getIllegalContent() + tmp.toString());
                            userDetailService.updateById(userDetailData);
                        }
                        // 恢复金额
                        demandService.txMoney(task.getTaskId());

                        // 更新状态
                        demandMapper.checkDemandContext(DemandStatus.FAILURE.getType(),
                                Constant.HANDLER_ID, task.getTaskId(), ans.toString());
                        taskMapper.updateTask(DemandStatus.FAILURE.getType(), task.getTaskId());
                    }
                } catch (JsonProcessingException e) {
                    log.error("任务序列化失败：{}", taskString);
                } catch (Exception e) {
                    log.error("任务失败：{}", taskString);
                }
            }
        }
    }

    /**
     *  每分钟 提交任务到队列
     */
    @Scheduled(cron = "0 */1 * * * ?")
    public void commitTask() {
        // 队列大小
        int n = 10;
        log.info("执行提交任务");
        String key = RedisConstant.TASK;
        Long listSize = stringRedisTemplate.opsForList().size(RedisConstant.TASK);
        if (listSize == null || listSize < n) {
            int size = n;
            if (listSize != null) {
                size = (int) (size - listSize);
            }
            List<Task> tasks = taskMapper.listByPage(0, size,
                    DemandStatus.REVIEW.getType());
            if (tasks.size() == 0) {
                return;
            }

            List<String> lists = new LinkedList<>();
            for (Task task : tasks) {
                try {
                    lists.add(SerializeUtil.objectMapperToString(task));
                } catch (JsonProcessingException e) {
                    log.error("任务序列化失败");
                    throw new RuntimeException(e);
                }
            }
            stringRedisTemplate.opsForList().leftPushAll(key, lists);
        }
    }

    /**
     * 任务不超 5 个
     * @param task 任务
     */
    @Override
    public void saveTask(Task task) {
        task.setCreateTime(new Date());
        save(task);
    }
}
